package com.wanger.swc.config.myBatisPlus;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.InetAddress;
import java.net.URL;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: wanger
 * @Date: 2024/9/16 3:13
 * @Description: mybatis-plus相关配置
 */
@Slf4j
@Configuration
public class MybatisPlusConfig {
    /**
     * 配置分页拦截器 Bean。
     *
     * @return 返回配置好的 PaginationInnerInterceptor 实例，用于 MyBatis-Plus 的分页功能。
     */
    @Bean
    public PaginationInnerInterceptor paginationInterceptor() {
        return new PaginationInnerInterceptor();
    }

    /**
     * 定义自定义元对象处理器，用于在插入和修改操作时自动填充字段。
     */
    @Slf4j
    @Configuration
    public static class MyMetaObjectHandler implements MetaObjectHandler {

        /**
         * 填充字段缓存，用于减少反射的开销。
         */
        private static final Map<Class<?>, Map<FieldFill, List<FillDataInfo<?>>>> fillMap = new HashMap<>();

        /**
         * 插入元对象字段填充（用于插入时对指定字段的填充）
         *
         * @param metaObject 元对象
         */
        @Override
        public void insertFill(MetaObject metaObject) {
            fillFields(metaObject, FieldFill.INSERT);
        }

        /**
         * 更新元对象字段填充（用于更新时对指定字段的填充）
         *
         * @param metaObject 元对象
         */
        @Override
        public void updateFill(MetaObject metaObject) {
            fillFields(metaObject, FieldFill.UPDATE);
        }

        /**
         * 处理字段填充
         *
         * @param metaObject 元对象
         * @param fillType   填充类型
         */
        private void fillFields(MetaObject metaObject, FieldFill fillType) {
            Class<?> aClass = metaObject.getOriginalObject().getClass();//获取到目标类型
            Map<FieldFill, List<FillDataInfo<?>>> map = fillMap.get(aClass);//从缓存中查询是否有字段值填充
            if (CollUtil.isEmpty(map)) map = tryToGetAndCache(aClass);//缓存中没有则从目标类中尝试获取并缓存
            if (CollUtil.isEmpty(map)) return;//还是没有就直接返回
            List<FillDataInfo<?>> list = map.get(fillType);//根据添加或者修改获取需要填充的字段列表
            if (CollUtil.isEmpty(list)) return;//列表为空就返回
            list.forEach(fillData ->
                    this.strictInsertFill(//填充字段
                            metaObject,//元数据
                            fillData.getFieldName(),//字段名称
                            fillData.getFieldType(),//字段类型
                            getInstancesByType(aClass, fillData.getFieldType(), fillData.getFieldName())//根据类型获取新的实例
                    ));
        }

        /**
         * 尝试获取填充数据并缓存
         *
         * @param aClass 目标类
         * @return 填充数据
         */
        private Map<FieldFill, List<FillDataInfo<?>>> tryToGetAndCache(Class<?> aClass) {
            Map<FieldFill, List<FillDataInfo<?>>> map = tryToGetAndCacheImpl(aClass)//递归向上查找所有符合条件的字段列表
                    .stream()
                    .collect(Collectors.groupingBy(FillDataInfo::getFillType));//转换为map
            fillMap.put(aClass, map);//缓存
            return map;
        }

        /**
         * 递归向上获取所有需要添加的字段
         *
         * @param aClass 目标类
         * @return 字段列表
         */
        private List<FillDataInfo<?>> tryToGetAndCacheImpl(Class<?> aClass) {
            List<FillDataInfo<?>> list = new ArrayList<>();//字段列表
            if (Object.class != aClass) {//没有到达顶级父类
                for (Field field : aClass.getDeclaredFields()) {//获取所有字段并遍历
                    int modifiers = field.getModifiers();//获取字段修饰
                    if (Modifier.isStatic(modifiers)//非static修饰
                            || Modifier.isFinal(modifiers)//非final修饰
                            || Modifier.isTransient(modifiers)) continue;//非transient修饰
                    TableField tableField = field.getAnnotation(TableField.class);//获取字段上的注解
                    if (tableField != null && tableField.exist() && FieldFill.DEFAULT != tableField.fill()) {//注解不为空 ，字段存在，并且填充类型不为默认
                        if (FieldFill.INSERT_UPDATE == tableField.fill()) {//拆分INSERT_UPDATE为具体的插入与修改
                            list.add(new FillDataInfo<>(FieldFill.INSERT, field.getName(), field.getType()));//插入
                            list.add(new FillDataInfo<>(FieldFill.UPDATE, field.getName(), field.getType()));//修改
                        } else {
                            list.add(new FillDataInfo<>(tableField.fill(), field.getName(), field.getType()));//插入或者修改
                        }
                    }
                }
                list.addAll(tryToGetAndCacheImpl(aClass.getSuperclass()));//递归查找父类的并追加到当前列表
            }
            return list;
        }

        /**
         * 填充数据信息
         *
         * @param <T> 填充数据类型
         */
        @Data
        @AllArgsConstructor
        private static class FillDataInfo<T> {
            private FieldFill fillType;//填充类型，时插入时填充还是修改时填充
            private String fieldName;//字段名称
            private Class<T> fieldType;//字段类型
        }

        /**
         * 通过类型获取实例，比如 Date.class就返回 new Date()，BigInteger.class则返回BigInteger.ZERO等
         *
         * @param classType 类类型
         * @param fieldType 类型
         * @param fieldName 字段名称
         * @param <T>       类型
         * @return 实例
         */
        @SuppressWarnings("unchecked")
        private static <T> T getInstancesByType(Class<?> classType, Class<?> fieldType, String fieldName) {
            //常用类型
            if (fieldType == String.class) {
                return (T) "";  // 返回空字符串实例
            }

            //时间系列
            else if (fieldType == Date.class) {
                return (T) new Date();  // 返回新的 Date 实例
            } else if (fieldType == LocalDate.class) {
                return (T) LocalDate.now();  // 返回新的 LocalDate  实例
            } else if (fieldType == LocalTime.class) {
                return (T) LocalTime.now();  // 返回新的 LocalTime 实例
            } else if (fieldType == LocalDateTime.class) {
                return (T) LocalDateTime.now();  // 返回新的 LocalDateTime 实例
            } else if (fieldType == Instant.class) {
                return (T) Instant.now();  // 返回新的 Instant  实例
            } else if (fieldType == java.sql.Date.class) {
                return (T) new java.sql.Date(System.currentTimeMillis());  // 返回新的 java.sql.Date  实例
            } else if (fieldType == java.sql.Time.class) {
                return (T) new java.sql.Time(System.currentTimeMillis());  // 返回新的 java.sql.Time  实例
            } else if (fieldType == java.sql.Timestamp.class) {
                return (T) new java.sql.Timestamp(System.currentTimeMillis());  // 返回新的 java.sql.Timestamp  实例
            }

            //数字系列
            else if (fieldType == Byte.class) {
                return (T) Byte.valueOf("0");  // 返回 Byte  类型的零值
            } else if (fieldType == Short.class) {
                return (T) Short.valueOf("0");  // 返回 Short 类型的零值
            } else if (fieldType == Integer.class) {
                return (T) Integer.valueOf(0);  // 返回 Integer 类型的零值
            } else if (fieldType == Long.class) {
                return (T) Long.valueOf(0L);  // 返回 Long 类型的零值
            } else if (fieldType == Float.class) {
                return (T) Float.valueOf(0);  // 返回 Float 类型的零值
            } else if (fieldType == Double.class) {
                return (T) Double.valueOf(0.0);  // 返回 Double 类型的零值
            } else if (fieldType == Character.class) {
                return (T) Character.valueOf(' ');  // 返回 Character  类型的 值
            } else if (fieldType == Boolean.class) {
                return (T) Boolean.valueOf(false);  // 返回 Boolean 类型的false值
            } else if (fieldType == BigInteger.class) {
                return (T) BigInteger.ZERO;  // 返回 BigInteger.ZERO 实例
            } else if (fieldType == BigDecimal.class) {
                return (T) BigDecimal.ZERO;  // 返回 BigDecimal.ZERO 实例
            }

            // 其他类型
            else if (fieldType == byte[].class) {
                return (T) new byte[0];  // 返回 byte[] 实例
            } else if (fieldType == char[].class) {
                return (T) new char[0];  // 返回 char[] 实例
            } else if (fieldType == UUID.class) {
                return (T) UUID.randomUUID();  // 返回 UUID 实例
            } else if (fieldType == URL.class) {
                return null;  // 返回 空 实例
            } else if (fieldType == InetAddress.class) {
                return null;  // 返回 空 实例
            }

            //未匹配到类型
            else {
                log.error("类型【{}】的【{}】字段对应的【{}】类型暂未配置默认实例，无法设置默认填充值！", classType.getName(), fieldName, fieldType);
                return null;
            }
        }

    }

}
